1use crate::ext::fancy_regex::*;
3use crate::scripts::base::*;
4use crate::types::*;
5use crate::utils::encoding::*;
6use crate::utils::escape::*;
7use anyhow::Result;
8use fancy_regex::Regex;
9use std::collections::BTreeSet;
10use std::collections::HashSet;
11use std::io::Write;
12use std::ops::{Deref, DerefMut, Index, IndexMut};
13use std::sync::Arc;
14
15#[derive(Debug)]
16pub struct KsBuilder {}
18
19impl KsBuilder {
20 pub fn new() -> Self {
22 Self {}
23 }
24}
25
26impl ScriptBuilder for KsBuilder {
27 fn default_encoding(&self) -> Encoding {
28 Encoding::Cp932
29 }
30
31 fn build_script(
32 &self,
33 buf: Vec<u8>,
34 _filename: &str,
35 encoding: Encoding,
36 _archive_encoding: Encoding,
37 config: &ExtraConfig,
38 _archive: Option<&Box<dyn Script>>,
39 ) -> Result<Box<dyn Script>> {
40 Ok(Box::new(KsScript::new(buf, encoding, config)?))
41 }
42
43 fn extensions(&self) -> &'static [&'static str] {
44 &["ks", "soc"]
45 }
46
47 fn script_type(&self) -> &'static ScriptType {
48 &ScriptType::Kirikiri
49 }
50}
51
52pub trait Node {
54 fn serialize(&self) -> String;
56}
57
58#[derive(Clone, Debug)]
59pub struct CommentNode(pub String);
61
62impl Node for CommentNode {
63 fn serialize(&self) -> String {
64 format!("; {}", self.0)
65 }
66}
67
68#[derive(Clone, Debug)]
69pub struct LabelNode {
71 pub name: String,
73 pub page: Option<String>,
75}
76
77impl Node for LabelNode {
78 fn serialize(&self) -> String {
79 if let Some(page) = &self.page {
80 format!("*{}|{}", self.name, page)
81 } else {
82 format!("*{}", self.name)
83 }
84 }
85}
86
87#[derive(Clone, Debug)]
88pub struct TextNode(pub String);
90
91impl Node for TextNode {
92 fn serialize(&self) -> String {
93 self.0.replace("[", "[[")
95 }
96}
97
98#[derive(Clone, Debug)]
99pub struct EmptyLineNode;
101
102impl Node for EmptyLineNode {
103 fn serialize(&self) -> String {
104 String::new()
105 }
106}
107
108#[derive(Clone, Debug)]
109pub enum TagAttr {
111 True,
113 Str(String),
115}
116
117#[derive(Clone, Debug)]
118pub struct TagNode {
120 pub name: String,
122 pub attributes: Vec<(String, TagAttr)>,
124}
125
126impl TagNode {
127 fn serialize_attributes(&self) -> String {
128 let mut parts = Vec::new();
129 for (key, value) in self.attributes.iter() {
130 match value {
131 TagAttr::True => {
132 parts.push(key.clone());
133 }
134 TagAttr::Str(val) => {
135 if val.contains(" ") || val.contains("=") {
136 parts.push(format!("{}=\"{}\"", key, val));
137 } else {
138 parts.push(format!("{}={}", key, val));
139 }
140 }
141 }
142 }
143 parts.join(" ")
144 }
145
146 fn ser_attributes_xml(&self) -> String {
147 let mut parts = Vec::new();
148 for (key, value) in self.attributes.iter() {
149 match value {
150 TagAttr::True => {
151 parts.push(key.clone());
152 }
153 TagAttr::Str(val) => {
154 parts.push(format!("{}=\"{}\"", key, escape_xml_attr_value(val)));
155 }
156 }
157 }
158 parts.join(" ")
159 }
160
161 pub fn set_attr(&mut self, key: &str, value: String) {
163 if let Some(attr) = self.attributes.iter_mut().find(|(k, _)| k == key) {
164 attr.1 = TagAttr::Str(value);
165 } else {
166 self.attributes.push((key.to_string(), TagAttr::Str(value)));
167 }
168 }
169
170 pub fn get_attr(&self, key: &str) -> Option<&TagAttr> {
172 self.attributes
173 .iter()
174 .find(|(k, _)| k == key)
175 .map(|(_, v)| v)
176 }
177
178 fn to_xml_tag(&self) -> String {
179 let attr_str = self.ser_attributes_xml();
180 if attr_str.is_empty() {
181 format!("<{}>", self.name)
182 } else {
183 format!("<{} {}>", self.name, attr_str)
184 }
185 }
186}
187
188impl Node for TagNode {
189 fn serialize(&self) -> String {
190 let attr_str = self.serialize_attributes();
191 if attr_str.is_empty() {
192 format!("[{}]", self.name)
193 } else {
194 format!("[{} {}]", self.name, attr_str)
195 }
196 }
197}
198
199#[derive(Clone)]
200pub struct CommandNode {
202 pub inner: TagNode,
204}
205
206impl Deref for CommandNode {
207 type Target = TagNode;
208
209 fn deref(&self) -> &Self::Target {
210 &self.inner
211 }
212}
213
214impl DerefMut for CommandNode {
215 fn deref_mut(&mut self) -> &mut Self::Target {
216 &mut self.inner
217 }
218}
219
220impl std::fmt::Debug for CommandNode {
221 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222 f.debug_struct("CommandNode")
223 .field("name", &self.inner.name)
224 .field("attributes", &self.inner.attributes)
225 .finish()
226 }
227}
228
229impl Node for CommandNode {
230 fn serialize(&self) -> String {
231 let attr_str = self.inner.serialize_attributes();
232 if attr_str.is_empty() {
233 format!("@{}", self.inner.name)
234 } else {
235 format!("@{} {}", self.inner.name, attr_str)
236 }
237 }
238}
239
240#[derive(Clone, Debug)]
241pub struct ScriptBlockNode(pub String);
243
244impl Node for ScriptBlockNode {
245 fn serialize(&self) -> String {
246 format!("[iscript]\n{}\n[endscript]", self.0)
247 }
248}
249
250#[derive(Clone, Debug)]
251pub enum ParsedLineNode {
253 Text(TextNode),
255 Tag(TagNode),
257}
258
259impl ParsedLineNode {
260 fn to_xml(&self) -> String {
261 match self {
262 ParsedLineNode::Text(text_node) => escape_xml_text_value(&text_node.0),
263 ParsedLineNode::Tag(tag_node) => {
264 if tag_node.name == "r" && tag_node.attributes.is_empty() {
265 "\n".to_string()
266 } else {
267 tag_node.to_xml_tag()
268 }
269 }
270 }
271 }
272
273 fn is_np(&self) -> bool {
274 matches!(self, ParsedLineNode::Tag(tag) if tag.name == "np")
275 }
276
277 fn is_tag(&self, name: &str) -> bool {
278 matches!(self, ParsedLineNode::Tag(tag) if tag.name == name)
279 }
280
281 fn set_attr(&mut self, key: &str, value: String) {
282 if let ParsedLineNode::Tag(tag) = self {
283 tag.set_attr(key, value);
284 }
285 }
286}
287
288impl Node for ParsedLineNode {
289 fn serialize(&self) -> String {
290 match self {
291 ParsedLineNode::Text(text_node) => text_node.serialize(),
292 ParsedLineNode::Tag(tag_node) => tag_node.serialize(),
293 }
294 }
295}
296
297#[derive(Clone, Debug)]
298pub struct ParsedLine(pub Vec<ParsedLineNode>);
300
301impl ParsedLine {
302 fn to_xml(&self) -> String {
303 let mut s = String::new();
304 for node in &self.0 {
305 s.push_str(&node.to_xml());
306 }
307 s
308 }
309}
310
311impl Deref for ParsedLine {
312 type Target = Vec<ParsedLineNode>;
313
314 fn deref(&self) -> &Self::Target {
315 &self.0
316 }
317}
318
319impl DerefMut for ParsedLine {
320 fn deref_mut(&mut self) -> &mut Self::Target {
321 &mut self.0
322 }
323}
324
325impl Node for ParsedLine {
326 fn serialize(&self) -> String {
327 self.0
328 .iter()
329 .map(|node| node.serialize())
330 .collect::<Vec<_>>()
331 .join("")
332 }
333}
334
335#[derive(Clone, Debug)]
336pub enum ParsedScriptNode {
338 Comment(CommentNode),
340 Label(LabelNode),
342 Command(CommandNode),
344 ScriptBlock(ScriptBlockNode),
346 Line(ParsedLine),
348 EmptyLine(EmptyLineNode),
350}
351
352impl ParsedScriptNode {
353 pub fn is_empty(&self) -> bool {
355 matches!(self, ParsedScriptNode::EmptyLine(_))
356 }
357
358 pub fn set_attr(&mut self, key: &str, value: String) {
360 if let ParsedScriptNode::Command(command) = self {
361 command.set_attr(key, value);
362 }
363 }
364}
365
366impl Node for ParsedScriptNode {
367 fn serialize(&self) -> String {
368 match self {
369 ParsedScriptNode::Comment(comment) => comment.serialize(),
370 ParsedScriptNode::Label(label) => label.serialize(),
371 ParsedScriptNode::Command(command) => command.serialize(),
372 ParsedScriptNode::ScriptBlock(script_block) => script_block.serialize(),
373 ParsedScriptNode::Line(line) => line.serialize(),
374 ParsedScriptNode::EmptyLine(empty_line) => empty_line.serialize(),
375 }
376 }
377}
378
379#[derive(Clone, Debug)]
380pub struct ParsedScript(pub Vec<ParsedScriptNode>);
382
383impl Deref for ParsedScript {
384 type Target = Vec<ParsedScriptNode>;
385
386 fn deref(&self) -> &Self::Target {
387 &self.0
388 }
389}
390
391impl DerefMut for ParsedScript {
392 fn deref_mut(&mut self) -> &mut Self::Target {
393 &mut self.0
394 }
395}
396
397impl Index<usize> for ParsedScript {
398 type Output = ParsedScriptNode;
399
400 fn index(&self, index: usize) -> &Self::Output {
401 &self.0[index]
402 }
403}
404
405impl IndexMut<usize> for ParsedScript {
406 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
407 if index < self.0.len() {
408 &mut self.0[index]
409 } else {
410 self.0.push(ParsedScriptNode::EmptyLine(EmptyLineNode));
411 self.0.last_mut().unwrap()
412 }
413 }
414}
415
416impl Node for ParsedScript {
417 fn serialize(&self) -> String {
418 self.0
419 .iter()
420 .map(|node| node.serialize())
421 .collect::<Vec<_>>()
422 .join("\n")
423 }
424}
425
426lazy_static::lazy_static! {
427 static ref LINE_SPLIT_RE: Regex = Regex::new(r"(\[.*?\])").unwrap();
428 static ref ATTR_RE: Regex = Regex::new("([a-zA-Z0-9_]+)(?:=(\"[^\"]*\"|'[^']*'|[^\\s\\]]+))?").unwrap();
429}
430
431pub struct Parser {
433 lines: Vec<String>,
434}
435
436impl Parser {
437 pub fn new(script: &str) -> Self {
441 let lines = script.lines().map(|s| s.to_string()).collect();
442 Self { lines }
443 }
444
445 fn parse_attributes(attr_str: &str) -> Result<Vec<(String, TagAttr)>> {
446 let mut attributes = Vec::new();
447 for cap in ATTR_RE.captures_iter(attr_str) {
448 let cap = cap?;
449 let key = cap
450 .get(1)
451 .ok_or(anyhow::anyhow!("Invalid attribute key"))?
452 .as_str()
453 .to_string();
454 let value = cap
455 .get(2)
456 .map(|v| {
457 let mut s = v.as_str().trim().to_string();
458 if s.starts_with("\"") && s.ends_with("\"") {
459 s = s[1..s.len() - 1].to_string();
460 } else if s.starts_with("'") && s.ends_with("'") {
461 s = s[1..s.len() - 1].to_string();
462 }
463 s = s.replace("`", "");
464 TagAttr::Str(s)
465 })
466 .unwrap_or(TagAttr::True);
467 attributes.push((key, value));
468 }
469 Ok(attributes)
470 }
471
472 fn parse_tag_or_command(content: &str) -> Result<TagNode> {
473 let parts = content.trim().split_ascii_whitespace().collect::<Vec<_>>();
474 let tag_name = parts[0].to_string();
475 let attr_string = parts[1..].join(" ");
476 let attrs = Self::parse_attributes(&attr_string)?;
477 Ok(TagNode {
478 name: tag_name,
479 attributes: attrs,
480 })
481 }
482
483 pub fn parse(&self, preserve_empty_lines: bool) -> Result<ParsedScript> {
487 let mut parsed_scripts = Vec::new();
488 let mut in_script_block = false;
489 let mut script_buffer = Vec::new();
490 let mut i = 0;
491 let line_count = self.lines.len();
492 while i < line_count {
493 let line = self.lines[i].trim();
494 i += 1;
495 if line.is_empty() {
496 if preserve_empty_lines {
497 parsed_scripts.push(ParsedScriptNode::EmptyLine(EmptyLineNode));
498 } else {
499 continue;
500 }
501 }
502 if in_script_block {
503 if line == "[endscript]" {
504 in_script_block = false;
505 parsed_scripts.push(ParsedScriptNode::ScriptBlock(ScriptBlockNode(
506 script_buffer.join("\n"),
507 )));
508 script_buffer.clear();
509 } else {
510 script_buffer.push(line.to_string());
511 }
512 continue;
513 }
514 if line == "[iscript]" {
515 in_script_block = true;
516 continue;
517 }
518 if line.starts_with(";") {
519 parsed_scripts.push(ParsedScriptNode::Comment(CommentNode(
520 line[1..].trim().to_string(),
521 )));
522 continue;
523 }
524 if line.starts_with("*") {
525 let parts: Vec<&str> = line.split('|').collect();
526 let label_name = parts[0][1..].trim().to_string();
527 let page = if parts.len() > 1 {
528 Some(parts[1..].join("|"))
529 } else {
530 None
531 };
532 parsed_scripts.push(ParsedScriptNode::Label(LabelNode {
533 name: label_name,
534 page,
535 }));
536 continue;
537 }
538 if line.starts_with("@") {
539 let content = &line[1..];
540 let tag_node = Self::parse_tag_or_command(content)?;
541 parsed_scripts.push(ParsedScriptNode::Command(CommandNode { inner: tag_node }));
542 continue;
543 }
544 let mut full_line = line.to_string();
545 while full_line.ends_with("\\") {
546 full_line.pop(); full_line = full_line.trim_end().to_string();
548 if i < line_count {
549 full_line.push(' ');
550 full_line.push_str(&self.lines[i].trim());
551 i += 1;
552 } else {
553 break; }
555 }
556 let mut parsed_line_nodes = Vec::new();
557 for part in LINE_SPLIT_RE.py_split(&full_line)? {
558 let part = part.trim();
559 if part.is_empty() {
560 continue;
561 }
562 if part.starts_with("[") && part.ends_with("]") {
563 if part == "[[r]]" {
564 parsed_line_nodes.push(ParsedLineNode::Text(TextNode("[r]".to_string())));
565 } else if part == "[[[[" {
566 parsed_line_nodes.push(ParsedLineNode::Text(TextNode("[[".to_string())));
567 } else if part.starts_with("[[") {
568 parsed_line_nodes
569 .push(ParsedLineNode::Text(TextNode(part[1..].to_string())))
570 } else {
571 parsed_line_nodes.push(ParsedLineNode::Tag(Self::parse_tag_or_command(
572 &part[1..part.len() - 1],
573 )?));
574 }
575 } else {
576 parsed_line_nodes.push(ParsedLineNode::Text(TextNode(part.to_string())));
577 }
578 }
579 if !parsed_line_nodes.is_empty() {
580 parsed_scripts.push(ParsedScriptNode::Line(ParsedLine(parsed_line_nodes)));
581 }
582 }
583 Ok(ParsedScript(parsed_scripts))
584 }
585}
586
587struct XMLTextParser {
588 str: String,
589 pos: usize,
590 lf: String,
591 no_np: bool,
592}
593
594impl XMLTextParser {
595 pub fn new(text: &str, lf: Option<String>) -> Self {
596 let lf = lf.unwrap_or_else(|| String::from("<r>"));
597 Self {
598 str: text.replace("\n", &lf),
599 pos: 0,
600 lf,
601 no_np: false,
602 }
603 }
604
605 fn no_np(mut self) -> Self {
606 self.no_np = true;
607 self
608 }
609
610 fn parse_tag(&mut self) -> Result<TagNode> {
611 let mut name = String::new();
612 let mut attributes = Vec::new();
613 let mut is_name = true;
614 let mut is_key = false;
615 let mut is_value = false;
616 let mut is_in_quote = false;
617 let mut key = String::new();
618 let mut value = String::new();
619 while let Some(c) = self.next() {
620 match c {
621 '>' => {
622 if !name.is_empty() {
623 return Ok(TagNode { name, attributes });
624 } else {
625 return Err(anyhow::anyhow!("Empty tag name"));
626 }
627 }
628 ' ' | '\t' => {
629 if is_name {
630 is_name = false;
631 is_key = true;
632 } else if is_key {
633 if !key.is_empty() {
634 attributes.push((key.clone(), TagAttr::True));
635 key.clear();
636 }
637 } else if is_value {
638 if is_in_quote {
639 value.push(c);
640 } else {
641 if !value.is_empty() {
642 attributes.push((key.clone(), TagAttr::Str(unescape_xml(&value))));
643 key.clear();
644 value.clear();
645 }
646 is_key = true;
647 is_value = false;
648 }
649 }
650 }
651 '"' => {
652 if is_in_quote {
653 is_in_quote = false;
654 if !value.is_empty() {
655 attributes.push((key.clone(), TagAttr::Str(unescape_xml(&value))));
656 key.clear();
657 value.clear();
658 }
659 is_key = true;
660 } else {
661 is_in_quote = true;
662 }
663 }
664 '=' => {
665 if is_key {
666 is_key = false;
667 is_value = true;
668 }
669 }
670 _ => {
671 if is_name {
672 name.push(c);
673 } else if is_key {
674 key.push(c);
675 } else if is_value {
676 value.push(c);
677 } else {
678 return Err(anyhow::anyhow!("Unexpected character in tag: {}", c));
679 }
680 }
681 }
682 }
683 Err(anyhow::anyhow!("Unexpected end of input while parsing tag"))
684 }
685
686 pub fn parse(mut self) -> Result<Vec<ParsedLine>> {
687 let mut lines = Vec::new();
688 let mut current_line = Vec::new();
689 let mut text = String::new();
690 while let Some(c) = self.next() {
691 match c {
692 '<' => {
693 if !text.is_empty() {
694 current_line.push(ParsedLineNode::Text(TextNode(unescape_xml(&text))));
695 text.clear();
696 }
697 let tag = self.parse_tag()?;
698 let is_r = tag.name == "r";
699 current_line.push(ParsedLineNode::Tag(tag));
700 if is_r {
701 lines.push(ParsedLine(current_line));
702 current_line = Vec::new();
703 }
704 }
705 _ => {
706 text.push(c);
707 if text.ends_with(&self.lf) {
708 if !text.is_empty() {
709 current_line.push(ParsedLineNode::Text(TextNode(unescape_xml(&text))));
710 text.clear();
711 }
712 lines.push(ParsedLine(current_line));
713 current_line = Vec::new();
714 }
715 }
716 }
717 }
718 if !text.is_empty() {
719 current_line.push(ParsedLineNode::Text(TextNode(unescape_xml(&text))));
720 }
721 if !self.no_np {
722 current_line.push(ParsedLineNode::Tag(TagNode {
723 name: "np".to_string(),
724 attributes: Vec::new(),
725 }));
726 }
727 lines.push(ParsedLine(current_line));
728 Ok(lines)
729 }
730
731 fn next(&mut self) -> Option<char> {
732 if self.pos < self.str.len() {
733 let c = self.str[self.pos..].chars().next()?;
734 self.pos += c.len_utf8();
735 Some(c)
736 } else {
737 None
738 }
739 }
740}
741
742#[derive(Debug)]
743pub struct KsScript {
745 bom: BomType,
746 tree: ParsedScript,
747 name_commands: Arc<HashSet<String>>,
748 message_commands: Arc<HashSet<String>>,
749 remove_empty_lines: bool,
750 hitret: bool,
751 lf: Option<String>,
752 message_tags: Arc<HashSet<String>>,
753}
754
755impl KsScript {
756 pub fn new(reader: Vec<u8>, encoding: Encoding, config: &ExtraConfig) -> Result<Self> {
762 let (text, bom) = decode_with_bom_detect(encoding, &reader, true)?;
763 let parser = Parser::new(&text);
764 let tree = parser.parse(!config.kirikiri_remove_empty_lines)?;
765 let hitret = if let Some(hitret) = config.kirikiri_ks_hitret {
766 hitret
767 } else {
768 let mut talk_count = 0u64;
769 let mut hitret_count = 0u64;
770 for node in tree.iter() {
771 match node {
772 ParsedScriptNode::Line(line) => {
773 for node in line.iter() {
774 if let ParsedLineNode::Tag(node) = node {
775 if node.name == "Talk" {
776 talk_count += 1;
777 } else if node.name == "Hitret" {
778 hitret_count += 1;
779 }
780 }
781 }
782 }
783 _ => {}
784 }
785 }
786 talk_count == hitret_count && talk_count > 3
787 };
788 Ok(Self {
789 bom: config.kirikiri_ks_bom.unwrap_or(bom),
790 tree,
791 name_commands: config.kirikiri_name_commands.clone(),
792 message_commands: config.kirikiri_message_commands.clone(),
793 remove_empty_lines: config.kirikiri_remove_empty_lines,
794 hitret,
795 lf: config.kirikiri_ks_lf.clone(),
796 message_tags: config.kirikiri_message_tags.clone(),
797 })
798 }
799}
800
801impl Script for KsScript {
802 fn default_output_script_type(&self) -> OutputScriptType {
803 OutputScriptType::Json
804 }
805
806 fn default_format_type(&self) -> FormatOptions {
807 FormatOptions::None
808 }
809
810 fn extract_messages(&self) -> Result<Vec<Message>> {
811 let mut messages = Vec::new();
812 let mut name = None;
813 let mut message = String::new();
814 if self.hitret {
815 for obj in self.tree.iter() {
816 match obj {
817 ParsedScriptNode::Line(line) => {
818 for node in line.iter() {
819 if node.is_tag("Talk") {
820 if let ParsedLineNode::Tag(tag) = &node {
821 if let Some(attr) = tag.get_attr("name") {
822 if let TagAttr::Str(s) = attr {
823 name = Some(s.to_string());
824 }
825 }
826 if name.is_none() {
827 for attr in &tag.attributes {
828 if let TagAttr::Str(value) = &attr.1 {
829 if !value.is_empty() && !value.is_ascii() {
830 name = Some(value.clone());
831 break;
832 }
833 }
834 }
835 }
836 if name.is_none() {
837 anyhow::bail!("name not found for Talk command");
838 }
839 continue;
840 }
841 } else if node.is_tag("Hitret") {
842 if let Some(lf) = self.lf.as_ref() {
843 message = message.replace(lf, "\n");
844 }
845 messages.push(Message {
846 name: if name.as_ref().is_some_and(|name| name == "心の声") {
847 None
848 } else {
849 name.clone()
850 },
851 message: message.trim_end_matches("<np>").to_owned(),
852 });
853 message.clear();
854 name = None;
855 continue;
856 } else if let ParsedLineNode::Tag(tag) = &node {
857 if self.message_tags.contains(&tag.name) {
858 for attr in &tag.attributes {
859 if let TagAttr::Str(value) = &attr.1 {
860 if !value.is_empty() && !value.is_ascii() {
861 messages.push(Message {
862 name: None,
863 message: value.clone(),
864 });
865 break;
866 }
867 }
868 }
869 }
870 }
871 if name.is_some() {
872 message.push_str(&node.to_xml());
873 }
874 }
875 }
876 _ => {}
877 }
878 }
879 return Ok(messages);
880 }
881 for obj in self.tree.iter() {
882 match obj {
883 ParsedScriptNode::Label(_) => {
884 if !message.is_empty() {
885 if let Some(lf) = self.lf.as_ref() {
886 message = message.replace(lf, "\n");
887 }
888 messages.push(Message {
889 name: name.clone(),
890 message: message.trim_end_matches("<np>").to_owned(),
891 });
892 message.clear();
893 name = None;
894 }
895 }
896 ParsedScriptNode::Line(line) => {
897 if !message.ends_with("<np>") {
898 message.push_str(&line.to_xml())
899 }
900 }
901 ParsedScriptNode::Command(cmd) => {
902 if self.name_commands.contains(&cmd.name) {
903 for attr in &cmd.attributes {
904 if let TagAttr::Str(value) = &attr.1 {
905 if !value.is_empty() && !value.is_ascii() {
906 name = Some(value.clone());
907 break; }
909 }
910 }
911 } else if self.message_commands.contains(&cmd.name) {
912 for attr in &cmd.attributes {
913 if let TagAttr::Str(value) = &attr.1 {
914 if !value.is_empty() && !value.is_ascii() {
915 messages.push(Message {
916 name: None,
917 message: value.clone(),
918 });
919 break; }
921 }
922 }
923 }
924 }
925 _ => {}
926 }
927 }
928 if !message.is_empty() {
929 if let Some(lf) = self.lf.as_ref() {
930 message = message.replace(lf, "\n");
931 }
932 messages.push(Message {
933 name,
934 message: message.trim_end_matches("<np>").to_owned(),
935 });
936 }
937 Ok(messages)
938 }
939
940 fn import_messages<'a>(
941 &'a self,
942 messages: Vec<Message>,
943 mut file: Box<dyn WriteSeek + 'a>,
944 _filename: &str,
945 encoding: Encoding,
946 replacement: Option<&'a ReplacementTable>,
947 ) -> Result<()> {
948 let mut mes = messages.iter();
949 let mut cur_mes = None;
950 let mut tree = self.tree.clone();
951 let mut i = 0;
952 if self.hitret {
953 let mut name_tag_loc = None;
954 let mut message_blocks = Vec::new();
955 let mut in_block = false;
956 cur_mes = mes.next();
957 while i < tree.len() {
958 match tree[i].clone() {
959 ParsedScriptNode::Line(line) => {
960 let mut j = 0;
961 while j < line.len() {
962 let node = line[j].clone();
963 if node.is_tag("Talk") {
964 if let ParsedLineNode::Tag(tag) = &node {
965 if let Some(attr) = tag.get_attr("name") {
966 if let TagAttr::Str(_) = attr {
967 name_tag_loc = Some((i, j, "name".to_string()));
968 }
969 }
970 if name_tag_loc.is_none() {
971 for attr in &tag.attributes {
972 if let TagAttr::Str(value) = &attr.1 {
973 if !value.is_empty() && !value.is_ascii() {
974 name_tag_loc = Some((i, j, attr.0.clone()));
975 break;
976 }
977 }
978 }
979 }
980 }
981 in_block = true;
982 j += 1;
983 continue;
984 } else if node.is_tag("Hitret") {
985 in_block = false;
986 let m = cur_mes
987 .take()
988 .ok_or(anyhow::anyhow!("Not enough messages"))?;
989 let (x, y, key) = name_tag_loc.take().ok_or(anyhow::anyhow!(
990 "Name tag not found for Talk command"
991 ))?;
992 let mut name =
993 m.name.clone().unwrap_or_else(|| "心の声".to_string());
994 if let Some(replacement) = replacement {
995 for (key, value) in replacement.map.iter() {
996 name = name.replace(key, value);
997 }
998 }
999 let mut li = &mut tree[x];
1000 if let ParsedScriptNode::Line(line) = &mut li {
1001 line[y].set_attr(&key, name);
1002 }
1003 let mut text = m.message.clone();
1004 if let Some(replacement) = replacement {
1005 for (key, value) in replacement.map.iter() {
1006 text = text.replace(key, value);
1007 }
1008 }
1009 cur_mes = mes.next();
1010 let mut mess =
1011 XMLTextParser::new(&text, self.lf.clone()).no_np().parse()?;
1012 let first_line_len = mess[0].len();
1013 let line_indexs =
1014 BTreeSet::from_iter(message_blocks.iter().map(|(i, _)| *i));
1015 let (start_x, start_y) =
1016 message_blocks.first().cloned().unwrap_or((i, j));
1017 let (end_x, end_y) =
1018 message_blocks.last().cloned().unwrap_or((x, y));
1019 {
1020 let li = &mut mess[0];
1021 let source_line = &tree[start_x];
1022 let source_line = match source_line {
1023 ParsedScriptNode::Line(line) => line,
1024 _ => return Err(anyhow::anyhow!("Expected line node")),
1025 };
1026 for z in 0..start_y {
1027 li.insert(z, source_line[z].clone());
1028 }
1029 }
1030 {
1031 let loc = mess.len() - 1;
1032 let li = &mut mess[loc];
1033 let source_line = &tree[end_x];
1034 let source_line = match source_line {
1035 ParsedScriptNode::Line(line) => line,
1036 _ => return Err(anyhow::anyhow!("Expected line node")),
1037 };
1038 for z in end_y + 1..source_line.len() {
1039 li.push(source_line[z].clone());
1040 }
1041 }
1042 let diff = mess.len() as isize - line_indexs.len() as isize;
1043 let common_lines = line_indexs.len().min(mess.len());
1044 let mut last_index = end_x;
1045 let message_lines = Vec::from_iter(line_indexs.iter().cloned());
1046 for z in 0..common_lines {
1047 tree[message_lines[z]] =
1048 ParsedScriptNode::Line(mess[z].clone());
1049 }
1050 for z in common_lines..message_lines.len() {
1051 tree.remove(message_lines[z] - (z - common_lines));
1052 }
1053 for z in common_lines..mess.len() {
1054 let new_line = ParsedScriptNode::Line(mess[z].clone());
1055 if last_index < tree.len() {
1056 tree.insert(last_index + 1, new_line);
1057 last_index += 1;
1058 } else {
1059 tree.push(new_line);
1060 }
1061 }
1062 i = (i as isize + diff) as usize;
1063 j = start_y + first_line_len + 2;
1064 message_blocks.clear();
1065 continue;
1066 } else if let ParsedLineNode::Tag(tag) = &node {
1067 if self.message_tags.contains(&tag.name) {
1068 for attr in &tag.attributes {
1069 if let TagAttr::Str(value) = &attr.1 {
1070 if !value.is_empty() && !value.is_ascii() {
1071 let m = cur_mes.take().ok_or(anyhow::anyhow!(
1072 "No enough messages."
1073 ))?;
1074 cur_mes = mes.next();
1075 let mut text = m.message.clone();
1076 if let Some(replacement) = replacement {
1077 for (key, value) in replacement.map.iter() {
1078 text = text.replace(key, value);
1079 }
1080 }
1081 let li = &mut tree[i];
1082 if let ParsedScriptNode::Line(line) = li {
1083 line[j].set_attr(&attr.0, text);
1084 }
1085 j += 1;
1086 continue;
1087 }
1088 }
1089 }
1090 }
1091 }
1092 if in_block {
1093 message_blocks.push((i, j));
1094 }
1095 j += 1;
1096 }
1097 }
1098 _ => {}
1099 }
1100 i += 1;
1101 }
1102 } else {
1103 let mut is_end = false;
1104 let mut name_command_block_line: Option<(usize, String)> = None;
1105 let mut message_lines = Vec::new();
1106 while i < tree.len() {
1107 match tree[i].clone() {
1108 ParsedScriptNode::Label(_) => {
1109 if !message_lines.is_empty() {
1110 let m: &Message = cur_mes
1111 .take()
1112 .ok_or(anyhow::anyhow!("Not enough messages"))?;
1113 if let Some((line, key)) = name_command_block_line.take() {
1114 let name = m
1115 .name
1116 .as_ref()
1117 .ok_or(anyhow::anyhow!("Name not found in message"))?;
1118 let mut name = name.clone();
1119 if let Some(replacement) = replacement {
1120 for (key, value) in replacement.map.iter() {
1121 name = name.replace(key, value);
1122 }
1123 }
1124 tree[line].set_attr(&key, name);
1125 }
1126 let mut text = m.message.to_owned();
1127 if let Some(replacement) = replacement {
1128 for (key, value) in replacement.map.iter() {
1129 text = text.replace(key, value);
1130 }
1131 }
1132 let mess = XMLTextParser::new(&text, self.lf.clone()).parse()?;
1133 let diff = mess.len() as isize - message_lines.len() as isize;
1134 let common_lines = message_lines.len().min(mess.len());
1135 let mut last_index = message_lines.last().cloned().unwrap_or(0);
1136 for j in 0..common_lines {
1137 tree[message_lines[j]] = ParsedScriptNode::Line(mess[j].clone());
1138 }
1139 for j in common_lines..message_lines.len() {
1140 tree.remove(message_lines[j] - (j - common_lines));
1141 }
1142 for i in common_lines..mess.len() {
1143 let new_line = ParsedScriptNode::Line(mess[i].clone());
1144 if last_index < tree.len() {
1145 tree.insert(last_index + 1, new_line);
1146 last_index += 1;
1147 } else {
1148 tree.push(new_line);
1149 }
1150 }
1151 i = (i as isize + diff) as usize;
1152 }
1153 message_lines.clear();
1154 is_end = false;
1155 if cur_mes.is_none() {
1156 cur_mes = mes.next();
1157 }
1158 }
1159 ParsedScriptNode::Line(line) => {
1160 if !is_end {
1161 message_lines.push(i);
1162 is_end = line.last().map(|e| e.is_np()).unwrap_or(false);
1163 }
1164 }
1165 ParsedScriptNode::Command(cmd) => {
1166 if self.name_commands.contains(&cmd.name) {
1167 for attr in &cmd.attributes {
1168 if let TagAttr::Str(value) = &attr.1 {
1169 if !value.is_empty() && !value.is_ascii() {
1170 name_command_block_line = Some((i, attr.0.clone()));
1171 break; }
1173 }
1174 }
1175 } else if self.message_commands.contains(&cmd.name) {
1176 for attr in &cmd.attributes {
1177 if let TagAttr::Str(value) = &attr.1 {
1178 if !value.is_empty() && !value.is_ascii() {
1179 let m = cur_mes
1180 .take()
1181 .ok_or(anyhow::anyhow!("Not enough messages"))?;
1182 let mut text = m.message.clone();
1183 if let Some(replacement) = replacement {
1184 for (key, value) in replacement.map.iter() {
1185 text = text.replace(key, value);
1186 }
1187 }
1188 tree[i].set_attr(&attr.0, text);
1189 cur_mes = mes.next();
1190 break; }
1192 }
1193 }
1194 }
1195 }
1196 _ => {}
1197 }
1198 i += 1;
1199 }
1200 if !message_lines.is_empty() {
1201 let m: &Message = cur_mes
1202 .take()
1203 .ok_or(anyhow::anyhow!("Not enough messages"))?;
1204 if let Some((line, key)) = name_command_block_line.take() {
1205 let name = m
1206 .name
1207 .as_ref()
1208 .ok_or(anyhow::anyhow!("Name not found in message"))?;
1209 let mut name = name.clone();
1210 if let Some(replacement) = replacement {
1211 for (key, value) in replacement.map.iter() {
1212 name = name.replace(key, value);
1213 }
1214 }
1215 tree[line].set_attr(&key, name);
1216 }
1217 let mut text = m.message.to_owned();
1218 if let Some(replacement) = replacement {
1219 for (key, value) in replacement.map.iter() {
1220 text = text.replace(key, value);
1221 }
1222 }
1223 let mess = XMLTextParser::new(&text, self.lf.clone()).parse()?;
1224 let common_lines = message_lines.len().min(mess.len());
1225 let mut last_index = message_lines.last().cloned().unwrap_or(0);
1226 for j in 0..common_lines {
1227 tree[message_lines[j]] = ParsedScriptNode::Line(mess[j].clone());
1228 }
1229 for j in common_lines..message_lines.len() {
1230 tree.remove(message_lines[j] - (j - common_lines));
1231 }
1232 for i in common_lines..mess.len() {
1233 let new_line = ParsedScriptNode::Line(mess[i].clone());
1234 if last_index < tree.len() {
1235 tree.insert(last_index + 1, new_line);
1236 last_index += 1;
1237 } else {
1238 tree.push(new_line);
1239 }
1240 }
1241 }
1242 }
1243 if cur_mes.is_some() || mes.next().is_some() {
1244 return Err(anyhow::anyhow!("Some messages were not processed."));
1245 }
1246 if self.remove_empty_lines {
1247 tree.retain(|node| !node.is_empty());
1248 }
1249 let s = tree.serialize() + "\n";
1250 let data = encode_string_with_bom(encoding, &s, false, self.bom)?;
1251 file.write_all(&data)?;
1252 Ok(())
1253 }
1254}